﻿Imports System.ComponentModel

Public Class PlayerTrackBar
    Inherits Control
    Protected Const BordHeight As Integer = 6

    Public Sub New()
        Me.MinValue = 0
        Me.MaxValue = 100
        Me.Value = 0
        Me.Width = 200
        Me.DoubleBuffered = True
    End Sub

    Private m_minValue As Integer, m_maxValue As Integer, currValue As Integer

    <Description("最小值"), Category("值")> _
    Public Property MinValue() As Integer
        Get
            Return m_minValue
        End Get
        Set(value As Integer)
            If value > MaxValue Then
                Return
            End If
            m_minValue = value
            Me.Refresh()
        End Set
    End Property

    <Description("最大值"), Category("值")> _
    Public Property MaxValue() As Integer
        Get
            Return m_maxValue
        End Get
        Set(value As Integer)
            If value < MinValue Then
                Return
            End If
            m_maxValue = value
            Me.Refresh()
        End Set
    End Property

    <Description("当前值"), Category("值")> _
    Public Property Value() As Integer
        Get
            Return currValue
        End Get
        Set(value As Integer)
            Dim preValue As Integer = currValue
            If value > MaxValue Then
                currValue = MaxValue
            ElseIf value < MinValue Then
                currValue = MinValue
            Else
                currValue = value
            End If
            Me.Refresh()
            If preValue <> currValue Then
                OnScroll()
            End If
        End Set
    End Property

    <Description("有值部分颜色"), Category("外观")> _
    Public Property FillColor As Color = Color.White

    <Description("无值部分颜色"), Category("外观")> _
    Public Property EmptyColor As Color = Color.FromArgb(135, 124, 124)

    <Description("滑块形状"), Category("外观")> _
    Public Property Shape() As TrackShape

    Protected ReadOnly Property ValueX() As Single
        Get
            Return (Value - MinValue) / CSng(MaxValue - MinValue) * BorderLength
        End Get
    End Property

    Protected ReadOnly Property BorderLength() As Integer
        Get
            Return Me.Width - BordHeight * 2
        End Get
    End Property

    Protected Sub DrawCircleTrack(g As Graphics, brush As SolidBrush)
        Using emptyPen As New Pen(EmptyColor)
            g.FillEllipse(brush, ValueX, 2, 2 * BordHeight, 2 * BordHeight)
            g.DrawEllipse(emptyPen, ValueX, 2, 2 * BordHeight, 2 * BordHeight)
        End Using
    End Sub

    Protected Sub DrawRectangles(g As Graphics, brush As SolidBrush)
        Using emptyPen As New Pen(EmptyColor)
            g.FillRectangle(brush, ValueX + BordHeight \ 2, 2, BordHeight, 2 * BordHeight)
            g.DrawRectangle(emptyPen, ValueX + BordHeight \ 2, 2, BordHeight, 2 * BordHeight)
        End Using
    End Sub

    ''' <summary>
    ''' 通过鼠标当前位置计算出进度值
    ''' </summary>
    ''' <param name="x">鼠标当前位置</param>
    ''' <returns></returns>
    Protected Function LocationX2Value(x As Integer) As Integer
        Return CInt(System.Math.Truncate((MaxValue - MinValue) / CSng(BorderLength) * (x - BordHeight) + MinValue))
    End Function

    Protected Overrides Sub OnPaint(e As PaintEventArgs)
        Using bit As New Bitmap(Me.Width, Me.Height)
            Using g As Graphics = Graphics.FromImage(bit)
                Using emptyBrush As New SolidBrush(EmptyColor)
                    g.FillRectangle(emptyBrush, BordHeight, 2 + BordHeight / 2.0F, BorderLength, BordHeight)
                End Using

                Using valueBrush As New SolidBrush(FillColor)
                    g.FillRectangle(valueBrush, BordHeight + 1.0F, 2 + BordHeight / 2.0F + 1.0F, ValueX - 2, BordHeight - 2)
                    Select Case Shape
                        Case TrackShape.Circle
                            DrawCircleTrack(g, valueBrush)
                            Exit Select
                        Case TrackShape.Rectanles
                            DrawRectangles(g, valueBrush)
                            Exit Select
                    End Select
                End Using
            End Using
            e.Graphics.DrawImage(bit, 0, 0)
        End Using
    End Sub

    Protected Overrides Sub OnMouseClick(e As MouseEventArgs)
        MyBase.OnMouseClick(e)
        If e.Button <> System.Windows.Forms.MouseButtons.Left Then
            Return
        End If
        Dim tempValue As Integer = LocationX2Value(e.X)
        If tempValue > MaxValue Then
            Value = MaxValue
        ElseIf tempValue < MinValue Then
            Value = MinValue
        Else
            Value = tempValue
        End If
    End Sub

    Protected Overrides Sub OnMouseMove(e As MouseEventArgs)
        MyBase.OnMouseMove(e)
        If e.Button <> System.Windows.Forms.MouseButtons.Left Then
            Return
        End If
        Dim tempValue As Integer = LocationX2Value(e.X)
        If tempValue > MaxValue Then
            Value = MaxValue
        ElseIf tempValue < MinValue Then
            Value = MinValue
        Else
            Value = tempValue
        End If
    End Sub

    <Description("当值变化后触发的事件"), Category("值")> _
    Public Event Scroll As EventHandler
    Public Overridable Sub OnScroll()
        RaiseEvent Scroll(Me, New EventArgs())
    End Sub

    Protected Overrides Sub OnResize(e As EventArgs)
        MyBase.OnResize(e)
        Me.Refresh()
    End Sub

    Public Enum TrackShape
        Circle
        Rectanles
    End Enum
End Class

